#ifndef MYJSON_MYJSON_H_
#define MYJSON_MYJSON_H_

#include <initializer_list>
#include <map>
#include <memory>
#include <string>
#include <vector>

namespace myjson {

enum JsonParse { STANDARD, COMMENTS };
class JsonValue;

class Json final {
public:
  // Json 支持的类型
  enum Type { NUL, NUMBER, BOOL, STRING, ARRAY, OBJECT };
  // array 和 object 的类型定义
  typedef std::vector<Json> array;
  typedef std::map<std::string, Json> object;

  // 针对不同 Json 值的构造器
  Json() noexcept;                // NUL
  Json(std::nullptr_t) noexcept;  // NUL
  Json(double value);             // NUMBER
  Json(int value);                // NUMBER
  Json(bool value);               // BOOL
  Json(const std::string &value); // STRING
  Json(std::string &&value);      // STRING
  Json(const char *value);        // STRING
  Json(const array &value);       // ARRAY
  Json(array &&value);            // ARRAY
  Json(const object &value);      // OBJECT
  Json(object &&value);           // OBJECT

  // 隐式构造: 具有 to_json() 函数的其他对象
  // class = decltype(&T::to_json) 定义了一个省略参数名的模板参数, 其默认值为
  // decltype(&T::to_json) 这就对 T 施加了限制, 实现了偏特化
  template <class T, class = decltype(&T::to_json)>
  Json(const T &t) : Json(t.to_json()) {}

  // 隐式构造: map-like 对象 (std::map, std::unordered_map 等)
  template <
      class M,
      typename std::enable_if<
          std::is_constructible<
              std::string, decltype(std::declval<M>().begin()->first)>::value &&
              std::is_constructible<
                  Json, decltype(std::declval<M>().begin()->second)>::value,
          int>::type = 0>
  Json(const M &m) : Json(object(m.begin(), m.end())) {}
  // 隐式构造: vector-like 对象 (std::list, std::vector, std::set 等)
  template <class V, typename std::enable_if<
                         std::is_constructible<
                             Json, decltype(*std::declval<V>().begin())>::value,
                         int>::type = 0>
  Json(const V &v) : Json(array(v.begin(), v.end())) {}

  //这可以防止 Json(some_pointer) 意外产生布尔值, 如果需要这种行为, 请使用
  // Json(bool(some_pointer))
  Json(void *) = delete;

  // 访问器
  Type type() const;

  bool is_null() const { return type() == NUL; }
  bool is_number() const { return type() == NUMBER; }
  bool is_bool() const { return type() == BOOL; }
  bool is_string() const { return type() == STRING; }
  bool is_array() const { return type() == ARRAY; }
  bool is_object() const { return type() == OBJECT; }

  // 如果这是一个数字的话, 就返回那个值, 否则的话就返回 0. 注意对于数字不区分
  // double 和 int, 因此一个 NUMBER-typed 对象可以使用 number_value() 和
  // int_value()
  double number_value() const;
  int int_value() const;

  // 如果这是一个布尔值，就返回那个值, 否则的话就返回 false.
  bool bool_value() const;
  // 如果这是一个字符串, 就返回这个字符串, 否则返回 "".
  const std::string &string_value() const;
  // 如果这是一个 array, 就返回这个 std::vector, 否则就返回一个空的 vector
  const array &array_items() const;
  // 如果这是一个 object, 就返回这个 std::map, 否则就返回一个空的 map
  const object &object_items() const;

  // 如果这是一个 array, 就返回 arr[i] 的引用, 否则就是 Json()
  const Json &operator[](size_t i) const;
  // 如果这是一个 object, 就返回 obj[key] 的引用, 否则就是 Json()
  const Json &operator[](const std::string &key) const;

  // 序列化
  void dump(std::string &out) const;
  std::string dump() const {
    std::string out;
    dump(out);
    return out;
  }

  // 解析。如果解析失败的话，返回 Json() 并且给 err 赋值一个错误信息
  static Json parse(const std::string &in, std::string &err,
                    JsonParse strategy = JsonParse::STANDARD);
  static Json parse(const char *in, std::string &err,
                    JsonParse strategy = JsonParse::STANDARD) {
    if (in) {
      return parse(std::string(in), err, strategy);
    } else {
      err = "null input";
      return nullptr;
    }
  }
  // 解析多个对象，用空格连接或分隔
  static std::vector<Json>
  parse_multi(const std::string &in, std::string::size_type &parser_stop_pos,
              std::string &err, JsonParse strategy = JsonParse::STANDARD);

  static inline std::vector<Json>
  parse_multi(const std::string &in, std::string &err,
              JsonParse strategy = JsonParse::STANDARD) {
    std::string::size_type parser_stop_pos;
    return parse_multi(in, parser_stop_pos, err, strategy);
  }

  // 重载运算符
  bool operator==(const Json &rhs) const;
  bool operator<(const Json &rhs) const;
  bool operator!=(const Json &rhs) const { return !(*this == rhs); }
  bool operator<=(const Json &rhs) const { return !(rhs < *this); }
  bool operator>(const Json &rhs) const { return (rhs < *this); }
  bool operator>=(const Json &rhs) const { return !(*this < rhs); }

  /* has_shape(types, err)
   * 如果这是一个 JSON 对象，返回 true
   * 和每一项的类型，否则就返回 false 并设置错误信息
   */
  typedef std::initializer_list<std::pair<std::string, Type>> shape;
  bool has_shape(const shape &types, std::string &err) const;

private:
  std::shared_ptr<JsonValue> m_ptr;

}; // class Json

// 内部类结构 - JsonValue 对象不暴露给该 API 的用户
class JsonValue {
protected:
  friend class Json;
  friend class JsonInt;
  friend class JsonDouble;
  // 纯虚函数，子类中必须实现这些函数
  virtual Json::Type type() const = 0;
  virtual bool equals(const JsonValue *other) const = 0;
  virtual bool less(const JsonValue *other) const = 0;
  virtual void dump(std::string &out) const=0;
  virtual double number_value() const;
  virtual int int_value() const;
  virtual bool bool_value() const;
  virtual const std::string &string_value() const;
  virtual const Json::array &array_items() const;
  virtual const Json &operator[](size_t i) const;
  virtual const Json::object &object_items() const;
  virtual const Json &operator[](const std::string &key) const;
  virtual ~JsonValue() {}
}; // class JsonValue

} // namespace myjson
#endif // MYJSON_MYJSON_H_